from unittest import TestCase

from comp_arch.pipeline import get_pipeline_state


class TestRiscVPipelineTrivial(TestCase):
    def test_get_pipeline_state_no_instructions1(self):
        cycle = 1
        instructions = []
        result = get_pipeline_state(cycle, instructions)
        self.assertTrue(not result, result)

    def test_get_pipeline_state_no_instructions(self):
        cycle = 1
        instructions = []
        result = get_pipeline_state(cycle, instructions)
        self.assertTrue(not result, result)

    def test_get_pipeline_state_cycle1(self):
        cycle = 1
        instructions = [("ld", "x1", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_cycle2(self):
        cycle = 2
        instructions = [("ld", "x1", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_cycle5(self):
        cycle = 5
        instructions = [("ld", "x1", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0}},
            {"cycle": 3, "state": {"EX": 0}},
            {"cycle": 4, "state": {"MEM": 0}},
            {"cycle": 5, "state": {"WB": 0}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_done(self):
        cycle = 6
        instructions = [("ld", "x1", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0}},
            {"cycle": 3, "state": {"EX": 0}},
            {"cycle": 4, "state": {"MEM": 0}},
            {"cycle": 5, "state": {"WB": 0}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_done600(self):
        cycle = 600
        instructions = [("ld", "x1", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0}},
            {"cycle": 3, "state": {"EX": 0}},
            {"cycle": 4, "state": {"MEM": 0}},
            {"cycle": 5, "state": {"WB": 0}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)


class TestRiscVPipelineNonBlocking(TestCase):
    def test_get_pipeline_state_cycle1(self):
        cycle = 1
        instructions = [("ld", "x1", "x0"), ("ld", "x2", "x0")]
        expected = [{"cycle": 1, "state": {"IF": 0}}]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_cycle2(self):
        cycle = 2
        instructions = [("ld", "x1", "x0"), ("ld", "x2", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0, "IF": 1}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)

    def test_get_pipeline_state_cycle7(self):
        cycle = 7
        instructions = [("ld", "x1", "x0"), ("ld", "x2", "x0")]
        expected = [
            {"cycle": 1, "state": {"IF": 0}},
            {"cycle": 2, "state": {"ID": 0, "IF": 1}},
            {"cycle": 3, "state": {"EX": 0, "ID": 1}},
            {"cycle": 4, "state": {"EX": 1, "MEM": 0}},
            {"cycle": 5, "state": {"MEM": 1, "WB": 0}},
            {"cycle": 6, "state": {"WB": 1}},
        ]
        result = get_pipeline_state(cycle, instructions)
        self.assertEqual(result, expected)
